package com.example.mq.service.impl;

import com.example.mq.dto.UserDTO;
import com.example.mq.model.*;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * @author 邹宇杰
 * @email 2901570623@qq.com
 * @date 2022/3/17 22:15
 */
@Service("userService")
public class UserServiceImpl implements UserDetailsService {

    private Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    JPAQueryFactory queryFactory;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = queryFactory.select(QUser.user).from(QUser.user).where(QUser.user.username.eq(username)).fetchFirst();
        if(user != null){
            return new org.springframework.security.core.userdetails.User(user.getUsername(), new BCryptPasswordEncoder().encode(user.getPassword()), this.granted.apply(user.getId()));
        }
        throw new RuntimeException("不存在该用户");
    }

    private final Function<String, List<GrantedAuthority>> granted = ((userId)->{
        Set<String> sets = this.function.apply(userId);
        List<Permission> permissions = queryFactory.select(QPermission.permission).from(QPermission.permission).where(QPermission.permission.id.in(sets)).fetch();
        List<GrantedAuthority> grantedAuthorityList = new ArrayList<>();
        permissions.forEach((s)->{
            GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(s.getRolename());
            grantedAuthorityList.add(grantedAuthority);
        });
        return grantedAuthorityList;
    });

    private final Function<String, Set<String>> function = ((userId)->{
        List<UserDTO> userDTOS = this.supplier.get();
        Set<String> permissions = new HashSet<>();
        userDTOS.forEach((userDTO)->{
            if(userId.equals(userDTO.getUser())){
                permissions.addAll(userDTO.getPermissions());
            }
        });
        return permissions;
    });

    private final Supplier<List<UserDTO>> supplier = (()->{
        List<UserDTO> userDTOS = new ArrayList<>();

        List<User> userList = queryFactory.select(QUser.user).from(QUser.user).fetch();
        List<RoleUser> roleUserList = queryFactory.select(QRoleUser.roleUser).from(QRoleUser.roleUser).fetch();
        List<PermissionRole> permissionRoleList = queryFactory.select(QPermissionRole.permissionRole).from(QPermissionRole.permissionRole).fetch();
        userList.forEach((u)->{
            UserDTO userDTO = new UserDTO();
            Set<String> roles = new HashSet<>();
            roleUserList.forEach((ru)->{
                if(ru.getUid().equals(u.getId())){
                    roles.add(ru.getRid());
                }
            });
            Set<String> permissions = new HashSet<>();
            roles.forEach((r)->{
                permissionRoleList.forEach((pr)->{
                    if(r.equals(pr.getRid())){
                        permissions.add(pr.getPid());
                    }
                });
            });
            userDTO.setUser(u.getId());
            userDTO.setRoles(roles);
            userDTO.setPermissions(permissions);

            userDTOS.add(userDTO);
        });
        return userDTOS;
    });
}
